﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Linq.Expressions;
using RStein.PosterousReader.Common.ViewModelsHelpers;
using System.Collections.Generic;
using System.Runtime.Serialization;
using RStein.PosterousReader.WP.ViewModels.SpecialTypes;
using System.Threading;
using System.Diagnostics;

namespace RStein.PosterousReader.WP.ViewModels
{
  public abstract class ViewModelBase : PropertyNotificationBase, ITransientStateManager, IInitialize, IActivated, IDeactivated, IPersistentStateManager, IUniqueHostKeyReceiver
  {
      
      
      public ViewModelBase()
      {
                                
      }

      static ViewModelBase()
      {
        TransientStateHelper = new TransientStateHelper();
        PersistentStateHelper = new PersistentStateHelper();
        StorageService= new DefaultSimpleStorageProvider();
      }

      
      public static ITransientStateHelper TransientStateHelper
      {
        get;
        set;
      }

      public static IPersistentStateHelper PersistentStateHelper
      {
        get;
        set;
      }

      public static ISimpleStorageProvider StorageService
      {
        get;
        set;
      }

      public ViewModelBase(string pageTitle) : this()
      {
          PageTitle = pageTitle;
      }

      public string AppTitle
      {
          get;
          set;
      }

      public string PageTitle
      {
          get;
          set;
      }

      public bool SuppressValidating
      {
        get;
        set;
      }

      public bool HasValidData
      {
        get
        {
          return ValidateData();
        }
          
      }

      public virtual bool ValidateData()
      {
        return true;
      }

      public bool IsInvalidModel
      {
        get;
        set;
      }

      public string UniqueHostKey
      {
        get;
        set;        
      }  
      
      public void Init()
      {
        try
        {
          IsInvalidModel = true;
          AppTitle = GlobalConstants.APP_MAIN_TITLE;
          SuppressValidating = false;
          IsInvalidModel = false;
          DoInternalInit();
          ThreadPool.QueueUserWorkItem(_ =>
                                        {
                                          try
                                          {
                                            
                                            DoInternalAsyncInit();
                                            SynchContext.Send(__ => LoadPersistentState(), null);
                                          }
                                          catch (Exception e)
                                          {
                                            Debug.WriteLine(e);
                                            if (!isThreadAbortException(e))
                                            {
                                              throw;
                                            }
                                          }
                                        });
        }
        catch (Exception e)
        {
          Debug.WriteLine(e);
          throw;
        }

      }

      
      protected virtual void DoInternalAsyncInit()
      {        
      }

      protected virtual void DoInternalInit()
      {

      }

      public virtual void Activate()
      {
        if (IsAllInitDataLoaded() && IsInvalidModel)
        {
          Init();
        }
      }

      public virtual void Deactivate()
      {
        SavePersistentState();
      }
        
      public bool CanUseModel
      {
        get
        {
          return !IsInvalidModel && IsAllInitDataLoaded();
        }
      }

      protected virtual bool IsAllInitDataLoaded()
      {
        return true;
      }
                        
      protected virtual Object DoInternalSaveTransientState()
      {
        var state = TransientStateHelper.GetTransientData(this);


        if (state == null)
        {
          return state;
        }
          
        var retKnownTypesDictionary = new KnownTypesDictionary(state);
        return retKnownTypesDictionary;
          
           
            
      }

      protected virtual void DoInternalLoadTransientState(Object obj)
      {
        var state = obj as Dictionary<string, object>;
        
        if (state == null)
        {
          return;
        }

        TransientStateHelper.RestoreTransientData(this, state);
        if (!CanUseModel)
        {
          Init();
        }
      }

      private bool isThreadAbortException(Exception e)
      {
        Exception currentException = e;
        while (currentException != null)
        {
          if (currentException is ThreadAbortException)
          {
            return true;
          }
          currentException = currentException.InnerException;
        }

        return false;
      }

        
      Object ITransientStateManager.SaveState()
      {

        
        Object obj  = DoInternalSaveTransientState();        
        return obj;
        
      }

        

      void ITransientStateManager.LoadState(Object obj)
      {
        DoInternalLoadTransientState(obj);
      }


      public virtual void LoadPersistentState()
      {
        var savedState = StorageService.LoadValue(UniqueHostKey) as Dictionary<string, Object>;
        if (savedState != null)
        {
          PersistentStateHelper.SetPersistentData(this, savedState);
        }
      }

      public virtual void SavePersistentState()
      {

        Dictionary<string, Object> state = PersistentStateHelper.GetPersistentData(this);

        if (state == null)
        {
          return;
        }

        KnownTypesDictionary knownTypesState = new KnownTypesDictionary(state);
        StorageService.SaveValue(UniqueHostKey, knownTypesState);
        
      }

      
  }
}
